package xyz.zyl2020.websocket.handler;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import xyz.zyl2020.websocket.vo.MessageVo;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * WebSocket处理器
 *
 * @author ZhuYinglong
 * @date 2020/8/13 0013
 */
public class ChatWebSocketHandler extends TextWebSocketHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());
    public static final Map<String, WebSocketSession> sessionPools = new ConcurrentHashMap<>();
    public static final AtomicLong onlineNum = new AtomicLong();

    /**
     * 创建连接
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        onlineNum.incrementAndGet();
        log.info("创建连接, sessionId: {}, onlineNum: {}, sessionPools: {}", session.getId(), onlineNum.get(), sessionPools.size());
    }

    /**
     * 收到消息
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("收到消息, sessionId: {}, message: {}", session.getId(), message.getPayload());
        MessageVo messageVo = JSONObject.parseObject(message.getPayload(), MessageVo.class);
        if (StringUtils.isEmpty(messageVo.getToUser())) {
            // 重复上线，将原连接关闭
            WebSocketSession fromUserSession = sessionPools.get(messageVo.getFromUser());
            if(fromUserSession != null) {
                log.info("重复上线,将原连接关闭, sessionId: {}, user: {}", session.getId(), messageVo.getFromUser());
                sessionPools.remove(messageVo.getFromUser());
                fromUserSession.close();
            }
            sessionPools.put(messageVo.getFromUser(), session);
            log.info("用户上线, sessionId: {}, user: {}, onlineNum: {}, sessionPools: {}", session.getId(), messageVo.getFromUser(), onlineNum, sessionPools.size());
        } else {
            sendMessage(messageVo);
        }
    }

    /**
     * 连接异常
     *
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("连接异常, sessionId: {}", session.getId(), exception);
    }

    /**
     * 连接关闭
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        onlineNum.decrementAndGet();
        for (Map.Entry<String, WebSocketSession> entry : sessionPools.entrySet()) {
            if (entry.getValue().getId().equals(session.getId())) {
                sessionPools.remove(entry);
                break;
            }
        }
        log.info("连接关闭, sessionId: {}, status: {}, onlineNum: {}, sessionPools: {}", session.getId(), status, onlineNum, sessionPools.size());
    }

    /**
     * 发送消息
     *
     * @param MessageVo
     */
    public void sendMessage(MessageVo MessageVo) {
        String toUser = MessageVo.getToUser();
        WebSocketSession session = sessionPools.get(toUser);
        if (session == null) {
            log.info("发送消息失败，目标用户不在线, user: {}, message: {}", toUser, JSONObject.toJSONString(MessageVo));
        } else {
            sendMessage(session, MessageVo);
        }
    }

    /**
     * 发送消息
     *
     * @param session
     * @param messageVo
     */
    public void sendMessage(WebSocketSession session, MessageVo messageVo) {
        String messageVoJson = JSONObject.toJSONString(messageVo);
        log.info("发送消息, sessionId: {}, message: {}", session.getId(), messageVoJson);
        try {
            session.sendMessage(new TextMessage(messageVoJson));
        } catch (IOException e) {
            log.info("发送消息异常, sessionId: {}", session.getId(), e);
        }
    }
}
